/*
 *--------------------------------------------------------------------------
 *   File Name:	sched.c
 * 
 * Description:	none
 * 
 * 
 *      Author:	Zhao Yanbai [zhaoyanbai@126.com]
 * 
 *     Version:	1.0
 * Create Date: Tue Feb 10 11:53:21 2009
 * Last Update: Tue Feb 10 11:53:21 2009
 * 
 *--------------------------------------------------------------------------
 */

#include "sched.h"
#include "assert.h"

pTask		current;
Task		RootTsk __attribute__((__aligned__(PAGE_SIZE)));

//ListHead	tsk_list = LIST_HEAD_INIT(tsk_list);
/* 进程链表 */
LIST_HEAD(tsk_list);

pid_t	get_next_pid()
{
	static pid_t	g_pid = ROOT_TSK_PID;

	return g_pid++;
}

inline	void	load_cr3(pTask	tsk)
{
	//printk("tsk %08x cr3: %08x\n",tsk, tsk->cr3);
	asm("movl %%eax,%%cr3;"::"a"(tsk->cr3));
	//int j=10000; while(j--);
}

void	init_tsk_cr3(pTask tsk)
{
	tsk->cr3 = pa2va(get_phys_pages(1));

	if(tsk->cr3 == NULL)
		panic("failed init tsk cr3");

	memset(tsk->cr3, 0, PAGE_SIZE);
	memcpy((void *)tsk->cr3, (void*)system.pgd, PAGE_SIZE);
	tsk->cr3 = (void *)va2pa(tsk->cr3);
}

void	init_root_tsk()
{
	int i;
	RootTsk.pid	= get_next_pid();
	RootTsk.ppid	= 0;

	for(i=0; i<NR_OPENS; i++)
		RootTsk.fps[i] = NULL;

	/* 这个时候还没有进程开始 */
	RootTsk.esp0	= tss.esp0;
	INIT_LIST_HEAD(&RootTsk.list);

	init_tsk_cr3(&RootTsk);
	load_cr3(&RootTsk);

	add_tsk2list(&RootTsk);
	current = &RootTsk;
/*
	// 栈
	void *stack = kmalloc(PAGE_SIZE);
	if(stack == NULL)
		panic("stack");
	stack = va2pa(stack);

	printk("Stack : %08x\n", stack);

	u32 *pde = pa2va(current->cr3);
	u32 *pte = (u32 *)kmalloc(PAGE_SIZE);
	if(pte == NULL)
		panic("root task stack pte");
	pte[1023] = stack + 7;
	printk("pte: %08x\n", pte);
	pde[(KRNLADDR>>22)-1] = va2pa(pte) + 7;


	printk("CR3:%08x\n", current->cr3);
	asm("movl %%eax,%%cr3;"::"a"(current->cr3));
*/
}

void	setup_tasks()
{
	INIT_LIST_HEAD(&tsk_list);

	/* 初始化第一个特殊的进程 */
	init_root_tsk();
#if 0
	add_task(test_taskB);
	add_task(test_taskA);
#endif
}


inline	pTask get_next_tsk(pTask tsk)
{
	assert(!list_is_empty(&tsk_list));

	pListHead p = tsk->list.next;
	if(p == &tsk_list)
	{
		p = tsk_list.next;
	}

	return get_tsk_from_list(p);

#if 0
	assert(&current->list == tsk_list.next);
	
	del_tsk_from_list(current);
	add_tsk2list(current);

	current	= get_tsk_from_list(tsk_list.next);
#endif
}

#if 1
inline	void set_esp0(pTask tsk)
{
	tss.esp0 = tsk->esp0;
}
inline void	switch_to()
{

	//printk("current:%08x esp0:%08x\n", current, current->esp0);
	load_cr3(current);
	set_esp0(current);
}
inline void context_switch(pTask prev, pTask next)
{
#if 1
	//pTask	last;
	unsigned long eax, ebx, ecx, edx, esi, edi;
	//asm("xchg %bx, %bx");
	asm volatile(
	"pushfl;"
	"pushl	%%ebp;"
	"movl	%%esp,%[prev_esp];"
	"movl	%[next_esp],%%esp;"
	"movl	$1f,%[prev_eip];"
	"pushl	%[next_eip];"
	"jmp	switch_to;"
	"1:"
	"popl	%%ebp;"
	"popfl;"
	:	[prev_esp] "=m"	(prev->esp),
		[prev_eip] "=m"	(prev->eip),
		"=a" (prev),	"=b" (ebx),	"=c" (ecx),
		"=d" (edx),	"=S" (esi),	"=D" (edi)
	:	[next_esp] "m"	(next->esp),
		[next_eip] "m"	(next->eip),
		[prev]	"a" (prev),
		[next]	"d" (next)
	:	"memory"
	);
#endif
#if 0
	asm("xchg %bx, %bx");
	asm volatile(
	"pushl	%%eax;"
	"pushl	%%ebx;"
	"pushl	%%ecx;"
	"pushl	%%edx;"
	"pushl	%%esi;"
	"pushl	%%edi;"
	"pushl	%%ebp;"
	"pushfl;"
	"movl	%%esp,%[prev_esp];"
	"movl	%[next_esp],%%esp;"
	"movl	$1f,%[prev_eip];"
	"pushl	%[next_eip];"
	"jmp	switch_to;"
	"1:"
	"popfl;"
	"popl	%%ebp;"
	"popl	%%edi;"
	"popl	%%esi;"
	"popl	%%edi;"
	"popl	%%edx;"
	"popl	%%ecx;"
	"popl	%%ebx;"
	"popl	%%eax;"
	:	[prev_esp] "=m"	(prev->esp),
		[prev_eip] "=m"	(prev->eip)
	:	[next_esp] "m"	(next->esp),
		[next_eip] "m"	(next->eip)
	:	"memory"
	);
#endif
}

unsigned long	schedule()
{
	pTask	tsk, prev, next;

	cli();	// For Safe.
	tsk = current;
	do
	{
		tsk = get_next_tsk(tsk);
	}while(tsk->state == TASK_EXITING); /* 简单实现 */

	if(current == tsk)
		return;

	//tsk = current;
	//printk("tsk:%08x\t", tsk);
	//current = tsk;
	prev = current;
	current = next = tsk;
	context_switch(prev, next);
}
#endif


inline void wake_up(pWaitQueue wq)
{
	
}

inline void sleep_on(pWaitQueue wq)
{

}




#if 0
inline void	save_tsk_regs(pPtRegs	regs)
{
	current->regs	= *regs;
}

unsigned long schedule(pPtRegs	regs)
{
	pTask	tsk;

	save_tsk_regs(regs);

	tsk = get_next_tsk();

	load_cr3(tsk);

	current = tsk;

	//printk("current:%08x ", current);
/*
	pListHead pos, tmp;
	list_for_each_safe(pos, tmp, &tsk_list)
	{
		printk(" -%08x- ", list_entry(pos, Task, list));
	}
	printk("current: %08x\n", current);

	if(current == &RootTsk)
	{
		current = list_entry(RootTsk.list.next, Task, list);
	}
	printk("current: %08x\n", current);
*/
#if 0
	if(current == 0xC7FE0000)
	{
		printk("shit\n");
		asm("xchg %bx,%bx");
	}
#endif

	return 0;
}
#endif

#if 0
unsigned long schedule(pPtRegs	regs)
{
	static int i=0;
	int t = 0;
	pTask	tsk = NULL;

	while(1)
	{
		i++;
		i = i%NR_TASKS;
		if(t++>NR_TASKS)
			break;

		if(tTasks[i] == NULL)
			continue;

		tsk = tTasks[i];

		if(tsk != current)
		{
			//asm("xchg %bx,%bx");
			current->regs	= *regs;
			//asm("xchg %bx,%bx");
			//*regs		= tsk->regs;
			//asm("xchg %bx,%bx");
			current		= tsk;
			//printk("tsk:%08x\n",tsk);
		}
		break;
	}

	return 0;
}
#endif

